/**
 *    Copyright (C) 2008  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef BITVECTORBITMAPREMOVETESTSUITE_HPP_INCLUDED
#define BITVECTORBITMAPREMOVETESTSUITE_HPP_INCLUDED

#include <unistd.h>

#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/portability/Stream.h>

#include <cubefs/core/bitvector.hpp>
#include "TestBase.hpp"


using namespace std;

namespace cubefs {
namespace core {
namespace tests {
namespace bitvector_ns {

class BitmapRemoveTest : public TestBase
{
    CPPUNIT_TEST_SUITE(BitmapRemoveTest);

    CPPUNIT_TEST(testSmallPathRemove);
    CPPUNIT_TEST(testSmallPathRemoveStart0);
    CPPUNIT_TEST(testInterpagePathRemove);
    CPPUNIT_TEST(testInterpagePathRemoveStart0);
    CPPUNIT_TEST(testInterpagePathRemoveAll);
    CPPUNIT_TEST(testInterpagePathRemoveWholeSubtree);

    CPPUNIT_TEST_SUITE_END();

public:
    BitmapRemoveTest() {}

    void testSmallPathRemove() {
        bv bv0(mgr);
        bv0.max_node_capacity() = 3;

        fill_bitvector(bv0, 1, 300);

        node_base* root = get_node(bv0.root());

        csize_t size1    = bv::get_max_key(root, 0);
        csize_t rank1    = bv::get_max_key(root, 1);
        csize_t bitsize1 = bv::get_max_key(root, 2);

        iterator from = get_first(root);

        from.move(2+4+1);

        iterator to = from;

        to.move(3 + 8 + 1);

        bv0.remove_bitmap_block(from, to, bv::PATH, txn);

        check_tree(root, size1 - 12, rank1 - 2, bitsize1 - 3, 4, 0);

        remove_tree(root);
    }

    void testSmallPathRemoveStart0() {
        bv bv0(mgr);
        bv0.max_node_capacity() = 3;

        fill_bitvector(bv0, 1, 300);

        node_base* root = get_node(bv0.root());

        csize_t size1    = bv::get_max_key(root, 0);
        csize_t rank1    = bv::get_max_key(root, 1);
        csize_t bitsize1 = bv::get_max_key(root, 2);

        iterator from = get_first(root);

        from.move(0);

        iterator to = from;

        to.move(2 + 4 + 1 + 3 + 8 + 1);

        bv0.remove_bitmap_block(from, to, bv::PATH, txn);

        check_tree(root, size1 - 12 - 7, rank1 - 2 - 1, bitsize1 - 3 - 2, 4, 0);

        remove_tree(root);
    }


    void testInterpagePathRemove() {
        bv bv0(mgr);
        bv0.max_node_capacity() = 3;

        fill_bitvector(bv0, 1, 300);

        node_base* root = get_node(bv0.root());

        csize_t size1    = bv::get_max_key(root, 0);
        csize_t rank1    = bv::get_max_key(root, 1);
        csize_t bitsize1 = bv::get_max_key(root, 2);

        iterator from = get_first(root);

        iterator to = from;

        from.move(2 + 4 + 1);

        index_t nodes = 130;

        skip_nodes(to, nodes, 4, 0);

        index_t size = 0, rank = 0, bitsize = 0;
        for (int c = 2; c < nodes + 1; c++) {
            rank += c;
            bitsize += c + 1;
            size += c + 1 + c*4 + 1;
        }

        bv0.remove_bitmap_block(from, to, bv::PATH, txn);

        root = get_node(bv0.root());

        check_tree(root, size1 - size, rank1 - rank, bitsize1 - bitsize, 4, 0);

        remove_tree(root);
    }


    void testInterpagePathRemoveStart0() {
        bv bv0(mgr);
        bv0.max_node_capacity() = 3;

        fill_bitvector(bv0, 1, 300);

        node_base* root = get_node(bv0.root());

        csize_t size1    = bv::get_max_key(root, 0);
        csize_t rank1    = bv::get_max_key(root, 1);
        csize_t bitsize1 = bv::get_max_key(root, 2);

        iterator from = get_first(root);

        iterator to = from;

        index_t nodes = 130;

        skip_nodes(to, nodes, 4, 0);

        index_t size = 0, rank = 0, bitsize = 0;
        for (int c = 1; c < nodes + 1; c++) {
            rank += c;
            bitsize += c + 1;
            size += c + 1 + c*4 + 1;
        }

        bv0.remove_bitmap_block(from, to, bv::PATH, txn);

        root = get_node(bv0.root());

        check_tree(root, size1 - size, rank1 - rank, bitsize1 - bitsize, 4, 0);

        remove_tree(root);
    }

    void testInterpagePathRemoveAll() {
        bv bv0(mgr);
        bv0.max_node_capacity() = 3;

        fill_bitvector(bv0, 1, 300);

        node_base* root = get_node(bv0.root());

        iterator from = get_first(root);

        iterator to = get_last(root);
        to.idx() = to.data()->header().get_size();
        to.setEof(true);

        bv0.remove_bitmap_block(from, to, bv::PATH, txn);

        CPPUNIT_ASSERT(bv0.root().is_null());
    }

    void testInterpagePathRemoveWholeSubtree() {
        bv bv0(mgr);
        bv0.max_node_capacity() = 3;

        fill_bitvector(bv0, 1, 300);

        node_base* root = get_node(bv0.root());

        iterator from = get_first(root);

        iterator to = get_last(root);
        to.idx() = to.data()->header().get_size();
        to.setEof(true);

        bv0.remove_bitmap_block(from, to, bv::PATH, txn);

        CPPUNIT_ASSERT(bv0.root().is_null());
    }

};

} //bitvector_ns
} //tests
} //core
} //cubefs

#endif // BITVECTORBITMAPREMOVETESTSUITE_HPP_INCLUDED
